﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Windows;
using System.Runtime.InteropServices;
using System.Windows.Threading;
using System.IO;

namespace Komunikator.Core
{
    class PacketReceiver
    {

        Socket socket;
        MainWindow mwHandle;
        SocketStreamReader ssr;
        SocketStreamWriter ssw;
        NetworkStream netStream;

        public PacketReceiver(MainWindow mwhandle, NetworkStream stream)
        {
            mwHandle = mwhandle;
            netStream = stream;

            ssr = new SocketStreamReader(netStream);
            ssw = new SocketStreamWriter(netStream);
        }


        public void ReceivePacket()
        {
            while (true)
            {
                try
                {
                    GGheader header = new GGheader();
                    header.type = ssr.ReadInt();
                    Thread.Sleep(2);
                    header.length = ssr.ReadInt();
                    Thread.Sleep(2);
                    switch (header.type)
                    {
                        case Packets.GG_WELCOME:

                            List<byte> gglogin80bytes = PrepareLoginPacket();

                            //wyslij ggheader pakietu logowania
                            GGheader headerToSend = new GGheader();
                            headerToSend.type = Packets.GG_LOGIN80;
                            headerToSend.length = gglogin80bytes.Count;

                            ssw.WriteGGpacket(headerToSend);
                            //Thread.Sleep(2);
                            ssw.WriteGGpacket(gglogin80bytes);
                            Thread.Sleep(2);

                            //pakiet listy kontaktow - tutaj pusta
                            GGheader header2 = new GGheader();
                            header2.type = 0x0012;
                            header2.length = 0;
                            ssw.WriteGGpacket(header2);
                            




                            break;
                        case Packets.GG_LOGIN80_OK: int unknown = ssr.ReadInt(); mwHandle.richTextBox1.Dispatcher.BeginInvoke(new MainWindow.UpdateTextDelegate(mwHandle.UpdateText), "logowanie OK!\n"); break;
                        case Packets.GG_LOGIN80_FAILED: int unknown1 = ssr.ReadInt(); mwHandle.richTextBox1.Dispatcher.BeginInvoke(new MainWindow.UpdateTextDelegate(mwHandle.UpdateText), "logowanie err!\n"); break;
                        case Packets.GG_LOGIN_FAILED: mwHandle.richTextBox1.Dispatcher.BeginInvoke(new MainWindow.UpdateTextDelegate(mwHandle.UpdateText), "logowanie err (old)!\n"); break;
                        default: mwHandle.richTextBox1.Dispatcher.BeginInvoke(new MainWindow.UpdateTextDelegate(mwHandle.UpdateText), header.type.ToString() + " " + header.length.ToString() + "\n"); //Thread safe comunication
                            break;

                    }
                    //MessageBox.Show("receiver");
                    Thread.Sleep(100);
                }
                catch (IOException e)
                {
                    mwHandle.richTextBox1.Dispatcher.BeginInvoke(new MainWindow.UpdateTextDelegate(mwHandle.UpdateText), "read timeout\n");
                    Thread.Sleep(100);
                }

            }

        }

        private List<byte> PrepareLoginPacket()
        {
            int seed = ssr.ReadInt(); //czytaj ziarno
            GGlogin800 gglogin = new GGlogin800(); // utworz pakiet logowania
            List<byte> gglogin80bytes = new List<byte>();
            gglogin.uin = HttpConnector.ggNumber;
            gglogin80bytes.AddRange(BitConverter.GetBytes(gglogin.uin));
            gglogin.language = ASCIIEncoding.ASCII.GetBytes("pl");
            gglogin80bytes.AddRange(gglogin.language);
            gglogin80bytes.Add(gglogin.hash_type);
            System.Buffer.BlockCopy(PasswordHash.GenerateHash(HttpConnector.ggPassword, seed), 0, gglogin.hash, 0, 20);
            gglogin.hash[20] = 0;
            gglogin80bytes.AddRange(gglogin.hash);
            gglogin80bytes.AddRange(BitConverter.GetBytes(gglogin.status));
            gglogin80bytes.AddRange(BitConverter.GetBytes(GGlogin800.flags));
            gglogin80bytes.AddRange(BitConverter.GetBytes(GGlogin800.features));
            gglogin80bytes.AddRange(BitConverter.GetBytes(gglogin.local_ip));
            gglogin80bytes.AddRange(BitConverter.GetBytes(gglogin.local_port));
            gglogin80bytes.AddRange(BitConverter.GetBytes(gglogin.external_ip));
            gglogin80bytes.AddRange(BitConverter.GetBytes(gglogin.external_port));
            gglogin80bytes.Add(gglogin.image_size);
            gglogin80bytes.Add(gglogin.unknown1);
            gglogin80bytes.AddRange(BitConverter.GetBytes(gglogin.version_len));
            gglogin80bytes.AddRange(gglogin.version);
            gglogin80bytes.AddRange(BitConverter.GetBytes(gglogin.description_size));
            return gglogin80bytes;
        }

        public static byte[] RawSerialize(object anything) //zamiana struct w bytes[] zeby przeslac przez siec
        {
            int rawsize = Marshal.SizeOf(anything);
            IntPtr buffer = Marshal.AllocHGlobal(rawsize);
            Marshal.StructureToPtr(anything, buffer, false);
            byte[] rawdatas = new byte[rawsize];
            Marshal.Copy(buffer, rawdatas, 0, rawsize);
            Marshal.FreeHGlobal(buffer);
            return rawdatas;
        } 

    }
}
